package com.yuyou.fn.analyze.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.plugins.Page;
import com.yuyou.fn.analyze.service.IBusinessStatisticsService;
import com.yuyou.fn.analyze.service.IProductStatisticsService;
import com.yuyou.fn.analyze.vo.*;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.service.ISiteConfigService;
import com.yuyou.fn.common.util.BeanUtils;
import com.yuyou.fn.common.util.Threads;
import com.yuyou.fn.common.util.Utils;
import com.yuyou.fn.educational.entity.CourseClass;
import com.yuyou.fn.educational.entity.StudentReg;
import com.yuyou.fn.educational.entity.Teacher;
import com.yuyou.fn.educational.service.ICourseClassService;
import com.yuyou.fn.educational.service.IStudentRegService;
import com.yuyou.fn.educational.service.ITeacherService;
import com.yuyou.fn.educational.vo.CourseClassQueryVo;
import com.yuyou.fn.platform.entity.AreaTeam;
import com.yuyou.fn.platform.entity.BusTeam;
import com.yuyou.fn.platform.entity.SysUser;
import com.yuyou.fn.platform.service.IAreaTeamService;
import com.yuyou.fn.platform.service.IBusTeamService;
import com.yuyou.fn.report.entity.CostOfGradeSubject;
import com.yuyou.fn.report.service.ICostOfGradeSubjectService;
import com.yuyou.fn.report.service.IRealIncomeOfClassService;
import com.yuyou.fn.report.vo.ClassAmountVo;
import com.yuyou.fn.report.vo.Extra;
import com.yuyou.fn.report.vo.GradeSubjectCostQueryVo;
import com.yuyou.fn.report.vo.RealIncomeClassQueryVo;
import com.yuyou.fn.settlement.constant.IncomeCategoryEnum;
import com.yuyou.fn.settlement.constant.Subjects;
import com.yuyou.fn.settlement.entity.ChangeRecord;
import com.yuyou.fn.settlement.entity.IncomeCategory;
import com.yuyou.fn.settlement.entity.MainAccount;
import com.yuyou.fn.settlement.entity.TradeProp;
import com.yuyou.fn.settlement.service.IChangeRecordService;
import com.yuyou.fn.settlement.service.ITradePropService;
import com.yuyou.fn.settlement.vo.ChangeRecordQueryVo;
import com.yuyou.fn.settlement.vo.FeeCategoryTreeMapVo;
import com.yuyou.fn.settlement.vo.MainAccountAmountVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;

import static com.yuyou.fn.settlement.constant.FeeCategoryEnum.SALARY_OF_COURSE;
import static com.yuyou.fn.settlement.constant.IncomeCategoryEnum.COURSE_INCOME;

/**
 *
 * ProductTarget 表数据服务层接口实现类
 *
 */
@Service
public class BusinessStatistsServiceImpl  implements IBusinessStatisticsService {
    @Resource
    private IChangeRecordService changeRecordService;

    @Resource
    private ITradePropService tradePropService;

    @Resource
    private ITeacherService teacherService;

    @Resource
    private ICourseClassService courseClassService;

    @Resource
    private IAreaTeamService areaTeamService;

    @Resource
    private IBusTeamService busTeamService;

    @Resource
    private ISiteConfigService siteConfigService;


    @Resource
    private IProductStatisticsService productStatisticsService;

    @Resource
    private IStudentRegService studentRegService;


    @Resource
    private IRealIncomeOfClassService realIncomeOfClassService;

    @Resource
    private ICostOfGradeSubjectService costOfGradeSubjectService;

    @Override
    public List<MainAccountCostAndIncome> findMainAccountCostAndIncome(Date startDate, Date endDate, List<MainAccount> mainAccountList) {
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        List<Long> mainAccountIds=BeanUtils.toList(mainAccountList,"mainAccountId");
        if (mainAccountIds == null || mainAccountIds.size() <= 0) {
            return Collections.EMPTY_LIST;
        }
        List<MainAccountCostAndIncome> mainAccountCostAndIncomeList=new ArrayList<MainAccountCostAndIncome>(mainAccountIds.size());

    /*    List<Callable<List<MainAccountAmountVo>>> taskList  = new ArrayList<>(mainAccountIds.size());

        for(final Long mainAccountId : mainAccountIds ){

            taskList.add(new Callable<List<MainAccountAmountVo>>() {
                @Override
                public List<MainAccountAmountVo> call() throws Exception {

                    ChangeRecordQueryVo changeRecordQueryVo=new ChangeRecordQueryVo();
                    changeRecordQueryVo.setMainAccountIds(Arrays.asList(mainAccountId));
                    changeRecordQueryVo.setStartDate(startDate);
                    changeRecordQueryVo.setEndDate(endDate);
                    changeRecordQueryVo.setSubjects(Arrays.asList("cost","real_income"));
                    changeRecordQueryVo.setDirection(0);
                    List<MainAccountAmountVo> mainAccountAmount=changeRecordService.findMainAccountAmount(changeRecordQueryVo);

                    return mainAccountAmount;
                }
            });
        }
        List<MainAccountAmountVo> retList=new ArrayList<>();
        try{
            List<Future<List<MainAccountAmountVo>>> futures = Threads.invokeAll(taskList);
            retList = new ArrayList<>(futures.size());
            for(Future<  List<MainAccountAmountVo>> f : futures ){
                if (Utils.checkListNotEmpty(f.get())){
                    retList.addAll(f.get());
                }
            }
        }catch (Exception e){
            throw new BusException("查询出错");
        }*/
        Map<Long,List<MainAccountAmountVo>> amountMap=new ConcurrentHashMap<>();

        List<Callable<List<MainAccountAmountVo>>> taskList  = new ArrayList<>(mainAccountIds.size());

        for(final Long mainAccountId : mainAccountIds ){

            taskList.add(new Callable<List<MainAccountAmountVo>>() {
                @Override
                public List<MainAccountAmountVo> call() throws Exception {
                    ChangeRecordQueryVo queryVo=new ChangeRecordQueryVo();
                    queryVo.setStartDate(startDate);
                    queryVo.setEndDate(endDate);
                    queryVo.setSubjects(Arrays.asList("cost","real_income"));
                    queryVo.setDirection(0);
                    queryVo.setMainAccountId(mainAccountId);
                    List<MainAccountAmountVo> mainAccountAmountVos=changeRecordService.findMainAccountAmount(queryVo);
                    return mainAccountAmountVos;
                }
            });
        }
        try {
            List<Future<List<MainAccountAmountVo>>> futures = Threads.invokeAll(taskList);
            for(Future<List<MainAccountAmountVo>> f : futures ){
                List<MainAccountAmountVo> mainAccountAmountVos=f.get();
                if (Utils.checkListNotEmpty(mainAccountAmountVos)){
                    MainAccountAmountVo mainAccount=f.get().get(0);
                    amountMap.put(mainAccount.getMainAccountId(),f.get());
                }

            }

        }catch (Exception e){
            throw new BusException("server error");
        }

        for (MainAccount mainAccount:mainAccountList){
            Long mainAccountId=mainAccount.getMainAccountId();
            MainAccountCostAndIncome mainAccountCostAndIncome=new MainAccountCostAndIncome();
            BigDecimal cost=BigDecimal.ZERO;
            BigDecimal income=BigDecimal.ZERO;
            BigDecimal profits=BigDecimal.ZERO;

            List<MainAccountAmountVo> one=amountMap.get(mainAccountId);
            if (one!=null){
                for (MainAccountAmountVo mainAccountAmountVo:one){
                    if ("cost".equals(mainAccountAmountVo.getSubject())){
                        cost=cost.add(mainAccountAmountVo.getAmount());
                    }else if ("real_income".equals(mainAccountAmountVo.getSubject())){
                        income=income.add(mainAccountAmountVo.getAmount());
                    }
                }
            }

            profits=income.subtract(cost);
            mainAccountCostAndIncome.setCost(cost);
            mainAccountCostAndIncome.setIncome(income);
            mainAccountCostAndIncome.setMainAcoountId(mainAccountId);
            mainAccountCostAndIncome.setProfits(profits);
            mainAccountCostAndIncome.setName(mainAccount.getName());
            mainAccountCostAndIncome.setTag(mainAccount.getTag());
            mainAccountCostAndIncome.setParentMainAccountId(mainAccount.getParentMainAccountId());
            mainAccountCostAndIncomeList.add(mainAccountCostAndIncome);
        }

        /*区域的话，将其底下的业务组相加*/
        Map<Long,List<MainAccountCostAndIncome>> groupMap=BeanUtils.toGroup(mainAccountCostAndIncomeList,"parentMainAccountId");
        for(MainAccountCostAndIncome mainAccountCostAndIncome:mainAccountCostAndIncomeList){
            if ("areaTeam".equals(mainAccountCostAndIncome.getTag())){
                if (groupMap.get(mainAccountCostAndIncome.getMainAcoountId())!=null){
                    List<MainAccountCostAndIncome> busTeamCostAndIncomeList=groupMap.get(mainAccountCostAndIncome.getMainAcoountId());
                    for (MainAccountCostAndIncome busTeamCostAndIncome:busTeamCostAndIncomeList){
                        mainAccountCostAndIncome.setCost(mainAccountCostAndIncome.getCost().add(busTeamCostAndIncome.getCost()));
                        mainAccountCostAndIncome.setIncome(mainAccountCostAndIncome.getIncome().add(busTeamCostAndIncome.getIncome()));
                        mainAccountCostAndIncome.setProfits(mainAccountCostAndIncome.getProfits().add(busTeamCostAndIncome.getProfits()));
                    }
                }
            }
        }

        return  mainAccountCostAndIncomeList;
    }


    @Override
    public CostDetailVo costDetail(Integer detailType, Long feeCategoryId, Long mainAccountId, Date startDate, Date endDate,SysUser sysUser) {
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        CostDetailVo costDetailVo=new CostDetailVo();
        if (detailType==1){/*子类成本*/
            costDetailVo.setCategoryMainAccountVoList(this.findChildCostByParentId(feeCategoryId,mainAccountId,startDate,endDate));
        }else if (detailType==0){/*流水明细*/
            List<ChangeRecord> changeRecordList=changeRecordService.findByCategoryIdAndMainAccountId(mainAccountId,0,"cost",startDate,endDate,feeCategoryId);
            costDetailVo.setChangeRecordList(changeRecordList);
        }else if (detailType==2){/*课酬明细*/
            List<TeacherClassCostVo> teacherClassCostVoList=this.classRemunerationDetail(mainAccountId,feeCategoryId,startDate,endDate);
            costDetailVo.setTeacherClassCostVoList(teacherClassCostVoList);
        }else if (detailType==3){
            costDetailVo.setCategoryMainAccountVoList(this.findBusCostByAreaTeam(mainAccountId,startDate,endDate,sysUser));
        }
        return costDetailVo;
    }

    @Override
    public CostDetailVo findCostDetail(Integer detailType, Long feeCategoryId, Long mainAccountId, Date startDate, Date endDate, SysUser sysUser,int pageNo,int pageSize) {
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        CostDetailVo costDetailVo=new CostDetailVo();
        if (detailType==1){/*子类成本*/
            costDetailVo.setCategoryMainAccountVoList(this.findChildCostByParentId(feeCategoryId,mainAccountId,startDate,endDate));
        }else if (detailType==0){/*流水明细*/
            ChangeRecordQueryVo changeRecordQueryVo=new ChangeRecordQueryVo();
            changeRecordQueryVo.setMainAccountId(mainAccountId);
            changeRecordQueryVo.setDirection(0);
            changeRecordQueryVo.setSubject("cost");
            changeRecordQueryVo.setStartDate(startDate);
            changeRecordQueryVo.setEndDate(endDate);
            changeRecordQueryVo.setCategoryId(feeCategoryId);
            Page<ChangeRecord> changeRecordPage=changeRecordService.findPageByQueryVo(changeRecordQueryVo,pageNo,pageSize);
            costDetailVo.setChangeRecordPage(changeRecordPage);
        }else if (detailType==2){/*课酬明细*/
            Page<TeacherClassCostVo> teacherClassCostVoPage=this.classRemunerationPage(mainAccountId,feeCategoryId,startDate,endDate,pageNo,pageSize);
            costDetailVo.setTeacherClassCostVoPage(teacherClassCostVoPage);
        }else if (detailType==3){
            costDetailVo.setCategoryMainAccountVoList(this.findBusCostByAreaTeam(mainAccountId,startDate,endDate,sysUser));
        }
        return costDetailVo;
    }

    @Override
    public IncomeDetailVo incomeDetail(Integer detailType, Long incomeCategoryId, Long mainAccountId, Date startDate, Date endDate,SysUser sysUser) {
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        IncomeDetailVo incomeDetailVo=new IncomeDetailVo();
        if (detailType==6){/*明细*/
            List<ChangeRecord> changeRecordList=changeRecordService.findByCategoryIdAndMainAccountId(mainAccountId,0,"real_income",startDate,endDate,incomeCategoryId);
            incomeDetailVo.setChangeRecordList(changeRecordList);
        }else if (detailType==7){/*课程收入*/
            List<ClassIncomeVo> classIncomeVoList=this.classIncomeDetail(Arrays.asList(mainAccountId),startDate,endDate);
            incomeDetailVo.setClassIncomeVoList(classIncomeVoList);
        }else if (detailType==8){
            incomeDetailVo.setCategoryMainAccountVoList(this.findBusIncomeByArea(mainAccountId,startDate,endDate,sysUser));
        }
        return incomeDetailVo;
    }

    @Override
    public IncomeDetailVo findIncomeDetail(Integer detailType, Long incomeCategoryId, Long mainAccountId, Date startDate, Date endDate, SysUser sysUser,int pageNo,int pageSize) {
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        IncomeDetailVo incomeDetailVo=new IncomeDetailVo();
        if (detailType==6){/*明细*/
            ChangeRecordQueryVo changeRecordQueryVo=new ChangeRecordQueryVo();
            changeRecordQueryVo.setMainAccountId(mainAccountId);
            changeRecordQueryVo.setDirection(0);
            changeRecordQueryVo.setSubject("real_income");
            changeRecordQueryVo.setCategoryId(incomeCategoryId);
            Page<ChangeRecord> changeRecordPage=changeRecordService.findPageByQueryVo(changeRecordQueryVo,pageNo,pageSize);
            incomeDetailVo.setChangeRecordPage(changeRecordPage);
        }else if (detailType==7){/*课程收入*/
            Page<ClassIncomeVo> classIncomeVoPage=this.classIncomePage(Arrays.asList(mainAccountId),startDate,endDate,pageNo,pageSize);
            incomeDetailVo.setClassIncomeVoPage(classIncomeVoPage);
        }else if (detailType==8){
            incomeDetailVo.setCategoryMainAccountVoList(this.findBusIncomeByArea(mainAccountId,startDate,endDate,sysUser));
        }
        return incomeDetailVo;
    }

    @Override
    public List<CategoryMainAccountVo> findBusCostByAreaTeam(Long areaTeamId, Date startDate, Date endDate,SysUser sysUser) {
        String mainAccountFeeCategory=siteConfigService.getConfigValueFromCache("main_account_feeCategory");
        List<FeeCategoryTreeMapVo> feeCategoryTreeMapVoList = JSONArray.parseArray(mainAccountFeeCategory,FeeCategoryTreeMapVo.class);
        List<BusTeam> busTeamList=busTeamService.findBusTeamByAreaTeamIds(Arrays.asList(areaTeamId));
        List<Long> busTeamIdList=BeanUtils.toList(busTeamList,"busTeamId");
        busTeamIdList=productStatisticsService.filterBusTeamByPermissions(busTeamIdList);
        List<ChangeRecord> busTeamCostList=changeRecordService.findByMainAccountIdsTimeDirectionSubject(busTeamIdList,startDate,endDate,0,"cost");
        List<CategoryMainAccountVo> busTeamcategoryMainAccountVoList=toMainAccountCostList(feeCategoryTreeMapVoList,busTeamCostList,areaTeamId);
        return  busTeamcategoryMainAccountVoList;
    }

    @Override
    public List<CategoryMainAccountVo> findCostByAllCategory(Long mainAccountId, Date startDate, Date endDate,SysUser sysUser) {
       // List<FeeCategoryTreeMapVo> feeCategoryTreeMapVoList= JsonArray.
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        String mainAccountFeeCategory=siteConfigService.getConfigValueFromCache("main_account_feeCategory");

        List<FeeCategoryTreeMapVo> feeCategoryTreeMapVoList = JSONArray.parseArray(mainAccountFeeCategory,FeeCategoryTreeMapVo.class);
        List<ChangeRecord> costList=changeRecordService.findByMainAccountIdsTimeDirectionSubject(Arrays.asList(mainAccountId),startDate,endDate,0,"cost");
        List<CategoryMainAccountVo> categoryMainAccountVoList=toMainAccountCostList(feeCategoryTreeMapVoList,costList,mainAccountId);

        AreaTeam areaTeam=areaTeamService.findById(mainAccountId);
        if (areaTeam!=null){
          List<CategoryMainAccountVo> busTeamcategoryMainAccountVoList=this.findBusCostByAreaTeam(areaTeam.getAreaTeamId(),startDate,endDate,sysUser);
            BigDecimal busTeamTotal=BigDecimal.ZERO;
            for (CategoryMainAccountVo categoryMainAccountVo:busTeamcategoryMainAccountVoList){
                busTeamTotal=busTeamTotal.add(categoryMainAccountVo.getTotalAmount());
            }
            CategoryMainAccountVo categoryMainAccountVo=new CategoryMainAccountVo();
            categoryMainAccountVo.setName("业务组成本总计");
            categoryMainAccountVo.setTotalAmount(busTeamTotal);
            categoryMainAccountVo.setCategoryId(-1L);
            categoryMainAccountVo.setDetailType(3);
            categoryMainAccountVoList.add(categoryMainAccountVo);
        }


        return categoryMainAccountVoList;
    }

    @Override
    public List<CategoryMainAccountVo> findChildCostByParentId(Long feeCategoryId, Long mainAccountId, Date startDate, Date endDate) {
        String mainAccountFeeCategory=siteConfigService.getConfigValueFromCache("main_account_feeCategory");
        List<FeeCategoryTreeMapVo> allFeeCategoryTreeMapVoList = JSONArray.parseArray(mainAccountFeeCategory,FeeCategoryTreeMapVo.class);

        List<FeeCategoryTreeMapVo> feeCategoryTreeMapVoList=this.findChildListByParentId(allFeeCategoryTreeMapVoList,feeCategoryId);
        if (feeCategoryTreeMapVoList==null || feeCategoryTreeMapVoList.size()<=0){
            return null;
        }
        List<Long> feeCategoryIdList=new ArrayList<Long>();
        fillAllFeeCategoryId(feeCategoryIdList,feeCategoryTreeMapVoList);
        List<ChangeRecord> costList=changeRecordService.findByCategoryIdsAndMainAccountIds(Arrays.asList(mainAccountId),0,"cost",startDate,endDate,feeCategoryIdList);
        List<CategoryMainAccountVo> categoryMainAccountVoList=toMainAccountCostList(feeCategoryTreeMapVoList,costList,mainAccountId);
        return categoryMainAccountVoList;
    }

    public List<CategoryMainAccountVo> toMainAccountCostList(List<FeeCategoryTreeMapVo> feeCategoryTreeMapVoList, List<ChangeRecord> costList,Long mainAccountId){
        List<CategoryMainAccountVo> categoryMainAccountVoList=new ArrayList<CategoryMainAccountVo>();
        if (feeCategoryTreeMapVoList==null ){
            return  categoryMainAccountVoList;
        }

        for (FeeCategoryTreeMapVo feeCategoryTreeMapVo:feeCategoryTreeMapVoList){

            CategoryMainAccountVo categoryMainAccountVo=new CategoryMainAccountVo();
            categoryMainAccountVo.setMainAccountId(mainAccountId);
            categoryMainAccountVo.setCategoryId(feeCategoryTreeMapVo.getFeeCategoryId());
            categoryMainAccountVo.setName(feeCategoryTreeMapVo.getName());
            BigDecimal totalAmount=BigDecimal.ZERO;
            if(costList!=null){
                Iterator<ChangeRecord> iterator=costList.iterator();
                while (iterator.hasNext()){
                    ChangeRecord changeRecord=iterator.next();
                    if (feeCategoryTreeMapVo.getFeeCategoryId().equals(changeRecord.getCategoryId())){
                        totalAmount=totalAmount.add(changeRecord.getAmount());
                    }
                }
            }
            if (feeCategoryTreeMapVo.getChildren()!=null && feeCategoryTreeMapVo.getChildren().size()>0){
                categoryMainAccountVo.setChildren(toMainAccountCostList(feeCategoryTreeMapVo.getChildren(),costList,mainAccountId));
                for (CategoryMainAccountVo childCategoryMainAccountVo:categoryMainAccountVo.getChildren()){
                    totalAmount=totalAmount.add(childCategoryMainAccountVo.getTotalAmount());
                }
                categoryMainAccountVo.setDetailType(1);/*子类信息*/
            }else {
                if (categoryMainAccountVo.getCategoryId().equals(SALARY_OF_COURSE.id)){/*任课课酬*/
                    categoryMainAccountVo.setDetailType(2);
                }else if (!categoryMainAccountVo.getCategoryId().equals(-1L)){/*-1l 区域统计旗下业务组，不需有明细*/
                    categoryMainAccountVo.setDetailType(0);
                }

            }
            categoryMainAccountVo.setTotalAmount(totalAmount);
            categoryMainAccountVoList.add(categoryMainAccountVo);
        }
        return categoryMainAccountVoList;
    }

    public void fillAllFeeCategoryId(List<Long> feeCategoryIdList,List<FeeCategoryTreeMapVo> feeCategoryTreeMapVoList){
        List<Long> feeCategoryIds=BeanUtils.toList(feeCategoryTreeMapVoList,"feeCategoryId");
        feeCategoryIdList.addAll(feeCategoryIds);
        for (FeeCategoryTreeMapVo feeCategoryTreeMapVo:feeCategoryTreeMapVoList){
            if (feeCategoryTreeMapVo.getChildren()!=null && feeCategoryTreeMapVo.getChildren().size()>0){
                fillAllFeeCategoryId(feeCategoryIdList,feeCategoryTreeMapVo.getChildren());
            }
        }
    }

    @Override
    public List<FeeCategoryTreeMapVo> findChildListByParentId(List<FeeCategoryTreeMapVo> feeCategoryTreeMapVoList,Long parentFeeCategoryId){
        List<FeeCategoryTreeMapVo> childFeeCategoryTreeMapVoList=null;
        for (FeeCategoryTreeMapVo feeCategoryTreeMapVo:feeCategoryTreeMapVoList){
            if (feeCategoryTreeMapVo.getFeeCategoryId().equals(parentFeeCategoryId)){
                childFeeCategoryTreeMapVoList=feeCategoryTreeMapVo.getChildren();
                break;
            }else if (feeCategoryTreeMapVo.getChildren()!=null){
                childFeeCategoryTreeMapVoList=findChildListByParentId(feeCategoryTreeMapVo.getChildren(),parentFeeCategoryId);
            }
        }
        return childFeeCategoryTreeMapVoList;
    }



    @Override
    public List<CategoryMainAccountVo> findIncomeByAllCategory(Long mainAccountId, Date startDate, Date endDate,SysUser sysUser) {
        if (startDate.getTime()>endDate.getTime()){
            throw new BusException("开始时间必须小于等于结束时间");
        }
        String mainAccoutIncomeCategory=siteConfigService.getConfigValueFromCache("main_account_incomeCategory");
        List<IncomeCategory> incomeCategoryList=JSONArray.parseArray(mainAccoutIncomeCategory,IncomeCategory.class);
        List<ChangeRecord> incomeList=changeRecordService.findByMainAccountIdsTimeDirectionSubject(Arrays.asList(mainAccountId),startDate,endDate,0,"real_income");
        List<CategoryMainAccountVo> categoryMainAccountVoList=toMainAccountIncomeList(incomeCategoryList,incomeList);
        AreaTeam areaTeam=areaTeamService.findById(mainAccountId);
        if (areaTeam!=null){
            BigDecimal totalAmount=BigDecimal.ZERO;
            List<CategoryMainAccountVo> busCategoryMainAccountVoList=this.findBusIncomeByArea(areaTeam.getAreaTeamId(),startDate,endDate,sysUser);
            for (CategoryMainAccountVo categoryMainAccountVo:busCategoryMainAccountVoList){
                totalAmount=totalAmount.add(categoryMainAccountVo.getTotalAmount());
            }
            CategoryMainAccountVo categoryMainAccountVo=new CategoryMainAccountVo();
            categoryMainAccountVo.setDetailType(8);
            categoryMainAccountVo.setCategoryId(-1L);
            categoryMainAccountVo.setName("业务组营收统计");
            categoryMainAccountVo.setTotalAmount(totalAmount);
            categoryMainAccountVoList.add(categoryMainAccountVo);
        }
        return categoryMainAccountVoList;
    }

    @Override
    public List<CategoryMainAccountVo> findBusIncomeByArea(Long areaTeamId, Date startDate, Date endDate, SysUser sysUser) {
        String mainAccoutIncomeCategory=siteConfigService.getConfigValueFromCache("main_account_incomeCategory");
        List<IncomeCategory> incomeCategoryList=JSONArray.parseArray(mainAccoutIncomeCategory,IncomeCategory.class);
        List<BusTeam> busTeamList=busTeamService.findBusTeamByAreaTeamIds(Arrays.asList(areaTeamId));
        List<Long> busTeamIdList=BeanUtils.toList(busTeamList,"busTeamId");
        busTeamIdList=productStatisticsService.filterBusTeamByPermissions(busTeamIdList);
        List<ChangeRecord> incomeList=changeRecordService.findByMainAccountIdsTimeDirectionSubject(busTeamIdList,startDate,endDate,0,"real_income");

        List<CategoryMainAccountVo> categoryMainAccountVoList=toMainAccountIncomeList(incomeCategoryList,incomeList);
        return categoryMainAccountVoList;
    }

    public List<CategoryMainAccountVo> toMainAccountIncomeList(List<IncomeCategory> incomeCategoryList, List<ChangeRecord> incomeList){
        List<CategoryMainAccountVo> categoryMainAccountVoList=new ArrayList<CategoryMainAccountVo>();
        if (incomeCategoryList==null ||incomeList==null){
            return  categoryMainAccountVoList;
        }

        for (IncomeCategory incomeCategory:incomeCategoryList) {
            Iterator<ChangeRecord> iterator=incomeList.iterator();
            CategoryMainAccountVo categoryMainAccountVo = new CategoryMainAccountVo();
            categoryMainAccountVo.setName(incomeCategory.getName());
            categoryMainAccountVo.setCategoryId(incomeCategory.getIncomeCategoryId());
            BigDecimal totalAmount = BigDecimal.ZERO;
            while (iterator.hasNext()){
                ChangeRecord changeRecord=iterator.next();
                if (incomeCategory.getIncomeCategoryId().equals(changeRecord.getCategoryId())){
                    totalAmount=totalAmount.add(changeRecord.getAmount());
                    iterator.remove();
                }
            }
            categoryMainAccountVo.setTotalAmount(totalAmount);
            if (incomeCategory.getIncomeCategoryId().equals(COURSE_INCOME.id)){
                categoryMainAccountVo.setDetailType(7);/*课程收入的明细依据这个显示归纳的信息*/
            }else{
                categoryMainAccountVo.setDetailType(6);
            }
            categoryMainAccountVoList.add(categoryMainAccountVo);
        }
        return categoryMainAccountVoList;
    }









    @Override
    public List<TeacherClassCostVo> classRemunerationDetail(Long mainAccountId,Long feeCategoryId, Date startDate, Date endDate) {
        List<TeacherClassCostVo> teacherClassCostVoList=new ArrayList<TeacherClassCostVo>();
        List<ChangeRecord> changeRecordList=changeRecordService.findByCategoryIdAndMainAccountId(mainAccountId,0,"cost",startDate,endDate,feeCategoryId);

        List<Long> tradeIdList=BeanUtils.toList(changeRecordList,"tradeId");
        List<TradeProp> tradePropList=tradePropService.findByTradeIds(tradeIdList);
        List<Long> classIdList=new ArrayList<Long>();
        List<Long> teacherIdList=new ArrayList<>();
        if (tradePropList!=null){
            for (TradeProp tradeProp:tradePropList){
                if ("teacherId".equals(tradeProp.getName())){
                    teacherIdList.add(Long.parseLong(tradeProp.getValue()));
                }else if ("classId".equals(tradeProp.getName())){
                    classIdList.add(Long.parseLong(tradeProp.getValue()));
                }
            }
        }


        Map<Long,CourseClass> courseClassMap=new HashMap<Long,CourseClass>();
        Map<Long,Teacher> teacherMap=new HashMap<Long, Teacher>();

        if (classIdList.size()>0){
            List<CourseClass> courseClasseList=courseClassService.findByIds(classIdList,"classId","className","busTeamId","areaTeamId","gradeId","gradeName","subjectId","subjectName","lectureAmount","studyingFee","regAmount");
            courseClassMap=BeanUtils.toMap(courseClasseList,"classId");
        }
        if (teacherIdList.size()>0){
            List<Teacher> teacherList=teacherService.findByIds(teacherIdList);
            teacherMap=BeanUtils.toMap(teacherList,"teacherId");
        }

        List<AreaTeam> areaTeamList=areaTeamService.findAllAreaTeam();
        Map<Long,AreaTeam> areaTeamMap=BeanUtils.toMap(areaTeamList,"areaTeamId");

        Example example=BusTeam.createExample();
        List<BusTeam>  busTeamList=busTeamService.findListByExample(example);
        Map<Long,BusTeam> busTeamMap=BeanUtils.toMap(busTeamList,"busTeamId");


        if (tradePropList!=null && tradePropList.size()>0){

            for (ChangeRecord changeRecord:changeRecordList){
                Iterator<TradeProp> iterator=tradePropList.iterator();
                Long tradeId=changeRecord.getTradeId();
                TeacherClassCostVo teacherClassCostVo=new TeacherClassCostVo();
                teacherClassCostVo.setClassHour(2);
                teacherClassCostVo.setTotalClassRemuneration(changeRecord.getAmount());
                //tag
                teacherClassCostVo.setSettlementDate(changeRecord.getEffectTime());
                teacherClassCostVo.setClassRemuneration(changeRecord.getAmount().divide(new BigDecimal(2)));
                while (iterator.hasNext()){
                    TradeProp tradeProp=iterator.next();
                    if (tradeId.equals(tradeProp.getTradeId())){
                        if ("teacherId".equals(tradeProp.getName())){
                            Teacher teacher=teacherMap.get(Long.parseLong(tradeProp.getValue()));
                            if (teacher!=null){
                                teacherClassCostVo.setTeacherId(teacher.getTeacherId());
                                teacherClassCostVo.setTeacherName(teacher.getTeacherName());
                                teacherClassCostVo.setIdNo(teacher.getIdNo());
                                teacherClassCostVo.setPhoneNo(teacher.getPhoneNo());
                            }
                        }else if ("classId".equals(tradeProp.getName())){
                            CourseClass courseClass=courseClassMap.get(Long.parseLong(tradeProp.getValue()));
                            if (courseClass!=null){
                                teacherClassCostVo.setClassId(courseClass.getClassId());
                                teacherClassCostVo.setClassName(courseClass.getClassName());
                                teacherClassCostVo.setAreaTeamId(courseClass.getAreaTeamId());
                                teacherClassCostVo.setAreaTeamName(areaTeamMap.get(courseClass.getAreaTeamId())==null?courseClass.getAreaTeamName():areaTeamMap.get(courseClass.getAreaTeamId()).getName());
                                teacherClassCostVo.setBusTeamId(courseClass.getBusTeamId());
                                teacherClassCostVo.setBusTeamName(busTeamMap.get(courseClass.getBusTeamId())==null?courseClass.getBusTeamName():busTeamMap.get(courseClass.getBusTeamId()).getName());
                            }
                        }else if ("lectureNo".equals(tradeProp.getName())){
                            teacherClassCostVo.setLectureNo(Integer.parseInt(tradeProp.getValue()));
                        }
                    }
                }
                if (teacherClassCostVo.getTeacherId()!=null){
                    teacherClassCostVoList.add(teacherClassCostVo);
                }
            }
        }
        return teacherClassCostVoList;
    }

    @Override
    public Page<TeacherClassCostVo> classRemunerationPage(Long mainAccountId, Long feeCategoryId, Date startDate, Date endDate,int pageNo,int pageSize) {

        GradeSubjectCostQueryVo gradeSubjectCostQueryVo=new GradeSubjectCostQueryVo();
        gradeSubjectCostQueryVo.setMainAccountId(mainAccountId);
        gradeSubjectCostQueryVo.setEndDate(endDate);
        gradeSubjectCostQueryVo.setFeeCategoryId(feeCategoryId);
        Page<CostOfGradeSubject> costOfGradeSubjectPage=costOfGradeSubjectService.findGradeSubjectCostPage(gradeSubjectCostQueryVo,pageNo,pageSize);

        Page<TeacherClassCostVo> teacherClassCostVoPage=Utils.newPage(costOfGradeSubjectPage);
        List<CostOfGradeSubject> costOfGradeSubjectList=costOfGradeSubjectPage.getRecords();
        if (costOfGradeSubjectList!=null){
            List<TeacherClassCostVo> teacherClassCostVoList=new ArrayList<TeacherClassCostVo>(costOfGradeSubjectList.size());
            for (CostOfGradeSubject costOfGradeSubject:costOfGradeSubjectList){
                TeacherClassCostVo teacherClassCostVo=new TeacherClassCostVo();
                teacherClassCostVo.setClassHour(2);
                teacherClassCostVo.setTotalClassRemuneration(costOfGradeSubject.getAmount());
                teacherClassCostVo.setSettlementDate(costOfGradeSubject.getCreateTime());
                teacherClassCostVo.setClassRemuneration(costOfGradeSubject.getAmount().divide(new BigDecimal(2)));
                String extraString=costOfGradeSubject.getExtra();
                Extra extra= JSONObject.parseObject(extraString,Extra.class);
                if (extra!=null ){
                    teacherClassCostVo.setTeacherId(extra.getTeacherId());
                    teacherClassCostVo.setTeacherName(extra.getTeacherName());
                    teacherClassCostVo.setIdNo(extra.getIdNo());
                    teacherClassCostVo.setPhoneNo(extra.getPhone());
                    teacherClassCostVo.setClassId(extra.getClassId());
                    teacherClassCostVo.setClassName(extra.getClassName());
                    teacherClassCostVo.setAreaTeamName(extra.getAreaTeamName());
                    teacherClassCostVo.setBusTeamName(extra.getBusTeamName());
                    teacherClassCostVo.setLectureNo(extra.getLectureNo());
                }
                teacherClassCostVoList.add(teacherClassCostVo);

            }
            teacherClassCostVoPage.setRecords(teacherClassCostVoList);
        }
        return teacherClassCostVoPage;
    }

    @Override
    public List<ClassIncomeVo> classIncomeDetail(List<Long> mainAccountIds , Date startDate, Date endDate) {

        List<ChangeRecord> changeRecordList=changeRecordService.findByCategoryIdsAndMainAccountIds(mainAccountIds,0, Subjects.REAL_INCOME ,startDate,endDate, Arrays.asList(IncomeCategoryEnum.COURSE_INCOME.id));
        if (changeRecordList==null || changeRecordList.size()<=0){
            return Collections.EMPTY_LIST;
        }
        List<Long> tradeIdList=BeanUtils.toList(changeRecordList,"tradeId");
        List<TradeProp> tradePropList = tradePropService.findValueByTradeIdsNames(tradeIdList,"classId" , "classLectureId","refundClassLectureIds");

        Map<String,List<TradeProp> > propName2tradeProp = BeanUtils.toGroup(tradePropList,"name");

        List<TradeProp> classIdPropList  = propName2tradeProp.get("classId");
        List<TradeProp> classLectureIdPropList  = propName2tradeProp.get("classLectureId");
        //List<TradeProp> refundClassLectureIdPropList  = propName2tradeProp.get("refundClassLectureIds");
        Map<Long,TradeProp> tradeId2ClassIdProp  = BeanUtils.toMap(classIdPropList,"tradeId");
        Map<Long,TradeProp> tradeId2ClassLectureIdProp  = BeanUtils.toMap(classLectureIdPropList,"tradeId");
       // Map<Long,TradeProp> tradeId2RefundClassLectureIdProp  = BeanUtils.toMap(refundClassLectureIdPropList,"tradeId");
        List<Long> classIdList = new ArrayList<>(tradePropList.size());
        if (classIdPropList!=null){
            for (TradeProp classIdProp : classIdPropList ){
                classIdList.add(Long.valueOf(classIdProp.getValue()));
            }
        }


        Map<Long,CourseClass> courseClassMap=new HashMap<Long,CourseClass>();
        if (classIdList.size()>0){
            List<CourseClass> courseClassesList=courseClassService.findByIds(classIdList,"classId","className","busTeamId","areaTeamId","gradeId","gradeName","subjectId","subjectName","lectureAmount","studyingFee","regAmount","productId");
            courseClassMap=BeanUtils.toMap(courseClassesList,"classId");
        }

        List<AreaTeam> areaTeamList=areaTeamService.findAllAreaTeam();
        Map<Long,AreaTeam> areaTeamMap=BeanUtils.toMap(areaTeamList,"areaTeamId");

        Example example=BusTeam.createExample();
        List<BusTeam>  busTeamList=busTeamService.findListByExample(example);
        Map<Long,BusTeam> busTeamMap=BeanUtils.toMap(busTeamList,"busTeamId");


        Map<String,ClassIncomeVo> classId2ClassIncomeVo = new HashMap<>();
        Map<String,Set<Long>> classId2ClassLectureId = new HashMap<>();
        List<Long> trackingIdList=BeanUtils.toList(changeRecordList,"trackingId");
        List<StudentReg> studentRegList=studentRegService.findByIds(trackingIdList,"regId","studentId","regStatus","payAmount","refundAmount");
        Map<Long,StudentReg> studentRegMap=BeanUtils.toMap(studentRegList,"regId");

        for (ChangeRecord changeRecord:changeRecordList) {
            Long tradeId = changeRecord.getTradeId();
            StudentReg studentReg=studentRegMap.get(changeRecord.getTrackingId());

            TradeProp classIdProp = tradeId2ClassIdProp.get(tradeId);
            TradeProp classLectureIdProp = tradeId2ClassLectureIdProp.get(tradeId);
           // TradeProp refundClassLectureIdProp =tradeId2RefundClassLectureIdProp.get(tradeId);
            if((classIdProp == null ||   classLectureIdProp == null)){//旧数据可能没有，不统计
                continue;
            }

            String classId = classIdProp.getValue();
            if (StringUtils.isEmpty(classId)){
                continue;
            }
            ClassIncomeVo  classIncomeVo = classId2ClassIncomeVo.get(classId);
            if(classIncomeVo == null ){
                CourseClass courseClass  = courseClassMap.get(Long.valueOf(classId));
                classIncomeVo = new ClassIncomeVo();
                classIncomeVo.setTotalIncomeAmount(BigDecimal.ZERO);
                classIncomeVo.setTotalRefundAmount(BigDecimal.ZERO);
                if (courseClass != null) {
                    classIncomeVo.setClassId(courseClass.getClassId());
                    classIncomeVo.setGradeId(courseClass.getGradeId());
                    classIncomeVo.setGradeName(courseClass.getGradeName());
                    classIncomeVo.setSubjectId(courseClass.getSubjectId());
                    classIncomeVo.setSubjectName(courseClass.getSubjectName());
                    classIncomeVo.setClassName(courseClass.getClassName());
                    classIncomeVo.setCompletedLectureAmount(courseClass.getCompletedLectureAmount());
                    classIncomeVo.setLectureAmount(courseClass.getLectureAmount());
                    classIncomeVo.setStudyingFee(courseClass.getStudyingFee());
                    classIncomeVo.setPeriodId(courseClass.getPeriodId());
                    classIncomeVo.setRegAmount(courseClass.getRegAmount());
                    classIncomeVo.setAreaTeamId(courseClass.getAreaTeamId());
                    classIncomeVo.setAreaTeamName(areaTeamMap.get(courseClass.getAreaTeamId()) == null ? courseClass.getAreaTeamName() : areaTeamMap.get(courseClass.getAreaTeamId()).getName());
                    classIncomeVo.setBusTeamId(courseClass.getBusTeamId());
                    classIncomeVo.setBusTeamName(busTeamMap.get(courseClass.getBusTeamId()) == null ? courseClass.getBusTeamName() : busTeamMap.get(courseClass.getBusTeamId()).getName());
                    classIncomeVo.setProductId(courseClass.getProductId());
                    classIncomeVo.setMainAccountId(courseClass.getBusTeamId());
                }
                classId2ClassIncomeVo.put(classId,classIncomeVo );
            }
            if (studentReg!=null){
          /*      if (changeRecord.getAmount().compareTo(BigDecimal.ZERO)<0){
                    classIncomeVo.setTotalRefundAmount(classIncomeVo.getTotalRefundAmount().add(changeRecord.getAmount()));
                }*/
                if (studentReg.getRegStatus()==0){
                    classIncomeVo.setTotalIncomeAmount(classIncomeVo.getTotalIncomeAmount().add(changeRecord.getAmount()));
                   // classIncomeVo.setTotalRefundAmount(classIncomeVo.getTotalRefundAmount().add(changeRecord.getAmount()));
                    classIncomeVo.setAdvanceAmount(studentReg.getPayAmount().subtract(studentReg.getRefundAmount()==null?BigDecimal.ZERO:studentReg.getRefundAmount()));

                }
            }



            //处理发生讲次

            Set<Long> classLectureIds = classId2ClassLectureId.get(classId);
            if(classLectureIds == null ){
                classLectureIds= new HashSet<Long>();
                classId2ClassLectureId.put(classId,classLectureIds);
            }
            if (classLectureIdProp!=null){
                classLectureIds.add(Long.valueOf(classLectureIdProp.getValue()));
            }
            classIncomeVo.setHappenLectureAmount(classLectureIds.size());
        }

        return new ArrayList<>(classId2ClassIncomeVo.values());
    }

    @Override
    public Page<ClassIncomeVo> classIncomePage(List<Long> mainAccountIdList, Date startDate, Date endDate,int pageNo,int pageSize) {
        CourseClassQueryVo courseClassQueryVo=new CourseClassQueryVo();
        courseClassQueryVo.setBusTeamIds(mainAccountIdList);
        Page<CourseClass> courseClassPage=courseClassService.findCourseClassByQuery(courseClassQueryVo,pageNo,pageSize);
        Page<ClassIncomeVo> classIncomeVoPage= Utils.newPage(courseClassPage);
        List<CourseClass> courseClassList=courseClassPage.getRecords();
        if (courseClassList!=null && courseClassList.size()>0){
            List<ClassIncomeVo> classIncomeVoList=new ArrayList<>(courseClassList.size());
            List<Long> classIds=BeanUtils.toList(courseClassList,"classId");
            List<StudentReg> studentRegList=studentRegService.findListByClassIds(classIds,0,"classId","payAmount","refundAmount");
            Map<Long,List<StudentReg>> regMap=BeanUtils.toGroup(studentRegList,"classId");

            RealIncomeClassQueryVo realIncomeClassQueryVo=new RealIncomeClassQueryVo();
            realIncomeClassQueryVo.setStartDate(startDate);
            realIncomeClassQueryVo.setEndDate(endDate);
            realIncomeClassQueryVo.setClassIds(classIds);
            List<ClassAmountVo> classAmountVoList=realIncomeOfClassService.findClassAmount(realIncomeClassQueryVo);
            Map<Long,ClassAmountVo> map=BeanUtils.toMap(classAmountVoList,"classId");
            for (CourseClass courseClass:courseClassList){
                ClassIncomeVo classIncomeVo=new ClassIncomeVo();
                BeanUtils.copyProperties(classIncomeVo,courseClass);
                classIncomeVo.setMainAccountId(courseClass.getBusTeamId());
                ClassAmountVo classAmountVo=map.get(courseClass.getClassId());
                if (classAmountVo!=null){
                    classIncomeVo.setHappenLectureAmount(classAmountVo.getHappenLectureAmount());
                    classIncomeVo.setTotalIncomeAmount(classAmountVo.getAmount());
                }
                BigDecimal advanceAmount=BigDecimal.ZERO;
                List<StudentReg> oneStudentRegList=regMap.get(courseClass.getClassId());
                if (oneStudentRegList!=null){
                    for (StudentReg studentReg:oneStudentRegList){
                        advanceAmount=advanceAmount.add(studentReg.getPayAmount().subtract(studentReg.getRefundAmount()));
                    }
                }
                classIncomeVo.setAdvanceAmount(advanceAmount);

                classIncomeVoList.add(classIncomeVo);
            }
            classIncomeVoPage.setRecords(classIncomeVoList);
        }
        return classIncomeVoPage;
    }
}